<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->


<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <script src="lib/simpleRequire.js"></script>
        <script src="lib/config.js"></script>
        <script src="lib/jquery.min.js"></script>
        <script src="lib/facePrint.js"></script>
        <script src="lib/testHelper.js"></script>
        <script src="lib/draggable.js"></script>
        <!-- <script src="ut/lib/canteen.js"></script> -->
        <link rel="stylesheet" href="lib/reset.css" />
    </head>
    <body>
        <style>
        </style>


        <div id="main_layout"></div>
        <div id="main_edge_cases"></div>
        <div id="main_self_layout"></div>
        <div id="main_dim_data_edge_cases"></div>


        <script>
            require([
                'echarts',
            ], function (echarts) {

                const MatrixClampOption = {
                    none: 0,
                    all: 1,
                    body: 2,
                    corner: 3,
                };

                var LEVEL_SIZE_1 = 15;
                var LEVEL_SIZE_2 = 20;
                var LEVEL_SIZE_3 = '10%';
                var LEVEL_SIZE_4 = '0%';
                var CELL_SIZE_1 = 30;
                var CELL_SIZE_2 = 0;
                var BODY_COMMON_COLOR = 'rgba(200, 150, 20, 0.1)';
                var BODY_R2_A2_COLOR = 'rgba(200, 155, 0)';
                var BODY_R1_B2_COLOR = 'rgba(200, 115, 200, 0.3)';
                var X_COMMON_COLOR = 'rgba(22, 188, 212, 0.1)';
                var X_T1_COLOR = 'rgba(12,122,250,0.8)';

                var bodyData = [
                    {
                        coord: ['R2', 'A3'],
                        mergeCells: true,
                    },
                    {
                        coord: [['R1', 'S'], 'A'],
                        itemStyle: {
                            color: 'rgb(220,240,130)',
                        }
                    },
                    {
                        coord: ['R1', ['B4', 'C']],
                        mergeCells: true,
                    },
                    {
                        coord: [['R1', 'R2'], ['B2', 'B3']],
                        itemStyle: {
                            borderWidth: 4,
                            borderColor: 'orange',
                            color: 'red',
                        },
                        mergeCells: true,
                    },
                    {
                        coord: ['R2', 'A2'],
                        itemStyle: {
                            borderWidth: 4,
                            borderColor: 'blue',
                            color: BODY_R2_A2_COLOR,
                        },
                        z2: 200,
                    },
                    {
                        coord: [['R2', 'T'], 'B2'], // Overlap span, should be ignored.
                        mergeCells: true,
                        itemStyle: {
                            borderWidth: 4,
                            borderColor: 'rgb(200, 152, 222)',
                            color: BODY_R1_B2_COLOR,
                        },
                        _desc: 'expand to cover all merged cells'
                    },
                    {
                        coord: ['T', ['A1', 'A31']], // Overlap span, should be ignored.
                        mergeCells: true,
                        itemStyle: {
                            borderColor: 'rgb(123,134,10)',
                            borderWidth: 3,
                            color: 'rgb(220,230,170)',
                        },
                        z2: 200,
                    },
                    {
                        coord: ['R2', 'E'],
                        value: 'very long long long text',
                        label: {
                            color: 'red',
                        }
                    },
                    {
                        coord: ['U', null],
                        coordClamp: true,
                        itemStyle: {
                            color: 'rgb(220,230,170)',
                        },
                    },
                    {
                        coord: [NaN, 'F'],
                        coordClamp: true,
                        mergeCells: true,
                    }
                ];

                var cornerData = [
                    {
                        coord: [null, -2],
                        coordClamp: true,
                        value: 'some',
                        mergeCells: true,
                    }
                ]

                const MATRIX_BACKGROUND_STYLE_MAP = {
                    do_nothing: {
                        backgroundStyle: {},
                        x: {
                            itemStyle: {},
                        },
                    },
                    style1: {
                        backgroundStyle: {
                            borderWidth: 5,
                        },
                        x: {
                            itemStyle: {
                                borderWidth: 2,
                                color: 'red',
                                borderColor: 'rgba(11,222,33)'
                            }
                        }
                    },
                    style2: {
                        backgroundStyle: {
                            borderWidth: 1,
                        },
                        x: {
                            itemStyle: {
                                borderWidth: 1,
                                color: 'none',
                                borderColor: 'blue'
                            }
                        }
                    },
                };

                // --- state ------
                let _xShowing = true;
                let _yShowing = true;
                let _convertFromPixelClampOpt = undefined;
                let _convertToPointCaseItem = null;
                let _matrixBgStyleIndex = 0;
                let _textOverflow = 'truncate'; // internal default value.
                // ----------------

                var option;
                option = {
                    backgroundColor: '#eee',
                    tooltip: {},
                    title: {
                        text: '',
                        right: 'center',
                    },
                    matrix: {
                        left: 120,
                        right: '29%',
                        tooltip: {
                            show: true,
                            formatter(params) {
                                return params.name;
                            }
                        },
                        x: {
                            label: {
                            },
                            itemStyle: {
                                color: X_COMMON_COLOR
                            },
                            levels: [null, {levelSize: LEVEL_SIZE_1}],
                            data: [
                                {
                                    value: 'R',
                                    children: ['R1', {value: 'R2', size: CELL_SIZE_1}]
                                },
                                {
                                    value: 'S'
                                },
                                {
                                    value: 'T',
                                    children: [
                                        {
                                            value: 'T1',
                                            itemStyle: {
                                                borderWidth: 3,
                                                borderColor: 'rgba(12,12,190)',
                                                color: X_T1_COLOR,
                                            },
                                            label: {
                                                fontSize: 22,
                                                color: '#fff',
                                                textBorderColor: '#333',
                                                textBorderWidth: 2,
                                            },
                                            children: ['T11']
                                        }
                                    ]
                                },
                                {
                                    value: 'long long header text 1',
                                    label: {
                                        color: 'rgb(211,111,0)',
                                    },
                                    children: [{
                                        value: 'long long header text 2',
                                        label: {
                                            color: 'rgb(211,81,0)',
                                        }
                                    }]
                                },
                                {
                                    value: 'U',
                                    size: 20,
                                },
                                {
                                    value: 'V',
                                    size: 20,
                                }
                            ]
                        },
                        y: {
                            levelSize: LEVEL_SIZE_2,
                            levels: [
                                null,
                                {levelSize: LEVEL_SIZE_4},
                                null,
                                null,
                                {levelSize: LEVEL_SIZE_3}
                            ],
                            data: [{
                                value: 'LLL',
                                children: [{
                                    value: 'LL',
                                    children: [
                                        {
                                            value: 'A',
                                            children: ['A1', 'A2', {
                                                value: 'A3',
                                                children: ['A31', 'A32']
                                            }]
                                        }, {
                                            value: 'B',
                                            children: ['B1', 'B2', 'B3', 'B4']
                                        }, {
                                            value: 'C',
                                        }, {
                                            value: 'D',
                                            size: CELL_SIZE_2,
                                        }
                                    ]
                                }, {
                                    value: 'E',
                                }, {
                                    value: 'F',
                                    itemStyle: {
                                        color: '#bbb'
                                    }
                                }]
                            }]
                        },
                        body: {
                            data: bodyData,
                            label: {
                            },
                            itemStyle: {
                                color: BODY_COMMON_COLOR
                            }
                        },
                        corner: {
                            itemStyle: {
                                borderWidth: 1,
                            },
                            data: cornerData,
                        }
                    },
                    graphic: {
                        elements: [{
                            right: 5,
                            y: 5,
                            id: 'info_bodyData',
                            type: 'text',
                            style: {
                                text: 'Check body cell merge and style:\n' + testHelper.printObject(bodyData, {lineBreakMaxColumn: 40}),
                                fontSize: 7,
                            }
                        }, {
                            left: 5,
                            y: 5,
                            id: 'info_cornerData',
                            type: 'text',
                            style: {
                                text: 'Check corner cell merge and style:\n' + testHelper.printObject(cornerData, {lineBreakMaxColumn: 40}),
                                fontSize: 7,
                            }
                        }, {
                            x: 120,
                            y: 5,
                            id: 'info2',
                            type: 'text',
                            style: {
                                text: [
                                    'Check background: ',
                                    ` BODY_COMMON_COLOR = ${BODY_COMMON_COLOR}`,
                                    ` BODY_R2_A2_COLOR = ${BODY_R2_A2_COLOR}`,
                                    ` BODY_R1_B2_COLOR = ${BODY_R1_B2_COLOR}`,
                                    ` X_COMMON_COLOR = ${X_COMMON_COLOR}`,
                                    ` X_T1_COLOR = ${X_T1_COLOR}`,
                                ].join('\n'),
                                fontSize: 7,
                            }
                        }]
                    },
                    grid: [{
                        id: 'aa',
                        coordinateSystem: 'matrix',
                        coord: ['R2', 'B3'],
                        top: 5,
                        left: 5,
                        right: 5,
                        bottom: 5,
                        containLabel: true,
                    }, {
                        id: 'bb',
                        coordinateSystem: 'matrix',
                        coord: ['R1', 'B4'],
                        top: 5,
                        left: 5,
                        right: 5,
                        bottom: 5,
                        containLabel: true,
                    }],
                    xAxis: [{
                        id: 'aa',
                        gridId: 'aa',
                        axisLabel: {fontSize: 9}
                    }, {
                        id: 'bb',
                        gridId: 'bb',
                        data: ['bb1', 'bb2', 'bb3'],
                        axisLabel: {fontSize: 9}
                    }],
                    yAxis: [{
                        id: 'aa',
                        gridId: 'aa',
                        interval: Infinity,
                        axisLabel: {fontSize: 9, showMinLabel: true, showMaxLabel: true,},
                    }, {
                        id: 'bb',
                        gridId: 'bb',
                        interval: Infinity,
                        axisLabel: {fontSize: 9, showMinLabel: true, showMaxLabel: true,},
                    }],
                    series: [{
                        type: 'scatter',
                        coordinateSystem: 'matrix',
                        symbolSize: 30,
                        data: [
                            ['R1', 'A1', 10], ['R2', 'A1', 20], ['R1', 'A2', 30]
                        ],
                        label: {
                            show: true,
                            formatter: params => {
                                return params.data[2];
                            }
                        }
                    }, {
                        // type: 'effectScatter',
                        type: 'scatter',
                        coordinateSystem: 'matrix',
                        symbolSize: function (val) {
                            return val[2] / 3;
                        },
                        data: [
                            ['R2', 'A2', 40], ['R1', 'A31', 50], ['R2', 'A3', 60]
                        ],
                    }, {
                        type: 'scatter',
                        name: 'right desc',
                        silent: true,
                        coordinateSystem: 'matrix',
                        symbolSize: 0,
                        symbolOffset: [0, 10],
                        label: {show: true, overflow: 'break', minMargin: 15},
                        labelLine: {show: true},
                        labelLayout: {
                            x: '73%',
                            moveOverlap: 'shiftY',
                            width: 70,
                        },
                        encode: {label: [0, 1, 2]},
                        data: [
                            ['T1', -2, `x.levels[3].levelSize: ${LEVEL_SIZE_1}`],
                            ['T11', -1, 'levelSize: average (not specified)'],
                            ['R2', -1, `size: ${CELL_SIZE_1}`],
                        ]
                    }, {
                        type: 'scatter',
                        name: 'left desc',
                        silent: true,
                        coordinateSystem: 'matrix',
                        symbolSize: 0,
                        symbolOffset: [0, 10],
                        label: {show: true, overflow: 'break', minMargin: 15},
                        labelLine: {show: true},
                        labelLayout: {x: '1%', width: 110, moveOverlap: 'shiftY'},
                        encode: {label: [0, 1, 2]},
                        data: [
                            [-3, 'A', `y.levelSize: ${LEVEL_SIZE_2}`],
                            [-2, 'A3', `y.levelSize: ${LEVEL_SIZE_2}`],
                            [-1, 'A31', `y.levels[4].levelSize: ${LEVEL_SIZE_3}`],
                            [-1, 'D', `size: ${CELL_SIZE_2}`],
                            [-4, 'E', `y.levels[2].levelSize: ${LEVEL_SIZE_4}`]
                        ]
                    },
                    {
                        type: 'line',
                        xAxisId: 'aa',
                        yAxisId: 'aa',
                        data: [[11, 22], [33, 44], [55, 66]],
                    }, {
                        type: 'bar',
                        xAxisId: 'bb',
                        yAxisId: 'bb',
                        data: [987, 583, 671],
                    }]
                };

                var chart = testHelper.create(echarts, 'main_layout', {
                    title: [
                        'Locator testing.',
                        'scatter, cartesian, with Matrix.',
                        'cell merging: should display **on the center** of the merged cell.',
                        'click on cell to call convertFromPixel - especially on span cell.',
                        'click on corner should correct.',
                        'tooltip can be displayed for text (consider overflow).',
                    ],
                    height: 500,
                    option: option,
                    inputsStyle: 'compact',
                    inputs: [
                        {
                            text: 'matrix.x show:',
                            type: 'select',
                            values: [true, false],
                            onchange() {
                                _xShowing = this.value;
                                chart.setOption({
                                    matrix: {
                                        x: {show: _xShowing},
                                    },
                                });
                                updateCaseView();
                            }
                        },
                        {
                            text: 'matrix.y show:',
                            type: 'select',
                            values: [true, false],
                            onchange() {
                                _yShowing = this.value;
                                chart.setOption({
                                    matrix: {
                                        y: {show: _yShowing},
                                    },
                                });
                                updateCaseView();
                            }
                        },
                        {
                            text: 'convertFromPixel clamp:',
                            type: 'select',
                            options: [
                                {value: undefined}
                            ].concat(Object.keys(MatrixClampOption).map(key => ({
                                text: key,
                                value: MatrixClampOption[key],
                            }))),
                            onchange() {
                                _convertFromPixelClampOpt = this.value;
                                updateCaseView();
                            },
                        },
                        {
                            type: 'select',
                            text: 'text overflow:',
                            values: ['truncate', 'break', 'none'],
                            onchange() {
                                _textOverflow = this.value;
                                chart.setOption({
                                    matrix: {
                                        x: {label: {overflow: _textOverflow}},
                                        y: {label: {overflow: _textOverflow}},
                                        body: {label: {overflow: _textOverflow}},
                                        corner: {label: {overflow: _textOverflow}},
                                    },
                                });
                                updateCaseView();
                            }
                        },
                        {
                            type: 'select',
                            text: 'switch style:',
                            values: Object.keys(MATRIX_BACKGROUND_STYLE_MAP),
                            onchange() {
                                const preset = MATRIX_BACKGROUND_STYLE_MAP[this.value];
                                chart.setOption({
                                    matrix: {
                                        backgroundStyle: preset.backgroundStyle,
                                        x: {
                                            itemStyle: preset.x.itemStyle,
                                        }
                                    }
                                });
                                updateCaseView();
                            }
                        },
                        {
                            type: 'select',
                            text: 'convertToPixel test cases:',
                            values: [
                                'do_nothing',
                                ['R2', 'A31'],
                                ['not_exists', 'A1'],
                                ['S', Infinity],
                                [1, 3],
                                ['R1', 'A'],
                                ['R1', 'A2'],
                                ['R1', 'B4'],
                                ['R1', 'B2'],
                                ['R1', 'C'],
                                ['R2', 'B3'],
                            ],
                            onchange() {
                                const caseItem = this.value;
                                if (caseItem === 'do_nothing') {
                                    return;
                                }
                                _convertToPointCaseItem = this.value;
                                updateCaseView();
                            }
                        },
                    ]
                });

                function updateCaseView() {
                    if (!_convertToPointCaseItem) {
                        return;
                    }
                    const result = chart.convertToPixel({matrixIndex: 0}, _convertToPointCaseItem);
                    updateConvertToPixelResult(result);
                }

                function updateConvertToPixelResult(result) {
                    console.log(result);
                    chart.setOption({
                        title: {
                            text: 'convertToPixel result: ' + testHelper.printObject(result)
                        },
                        graphic: {
                            elements: [{
                                id: 'result',
                                type: 'circle',
                                shape: {
                                    cx: result[0],
                                    cy: result[1],
                                    r: 20,
                                },
                                ignore: isNaN(result[0]) || isNaN(result[1]),
                                z: 1000,
                                style: {
                                    stroke: 'red',
                                    fill: null,
                                    lineWidth: 5,
                                    opacity: 0.8,
                                },
                                textContent: {
                                    style: {
                                        text: '⬅ convertToPixel result',
                                        fill: 'red',
                                    },
                                    z: 1000,
                                },
                                textConfig: {
                                    position: 'right'
                                },
                            }]
                        }
                    });
                }

                if (chart) {
                    chart.getZr().on('click', function (event) {
                        const point = [event.offsetX, event.offsetY];
                        let opt = null;
                        if (_convertFromPixelClampOpt != null) {
                            opt = {clamp: _convertFromPixelClampOpt};
                        }
                        const result = chart.convertFromPixel({matrixIndex: 0}, point, opt);
                        console.log('point', point, 'result', result);
                        chart.setOption({
                            title: {
                                text: 'convertFromPixel result: ' + testHelper.printObject(result)
                            }
                        });
                    });
                }

            });

        </script>







        <script>
            require([
                'echarts',
            ], function (echarts) {

                var LEVEL_SIZE_1 = 15;
                var LEVEL_SIZE_2 = 20;
                var LEVEL_SIZE_3 = '10%';
                var LEVEL_SIZE_4 = '0%';
                var CELL_SIZE_1 = 30;
                var CELL_SIZE_2 = 0;
                var BODY_COMMON_COLOR = 'rgba(200, 150, 20, 0.1)';
                var BODY_R2_A2_COLOR = 'rgba(200, 155, 0)';
                var BODY_R1_B2_COLOR = 'rgba(200, 115, 200, 0.3)';
                var X_COMMON_COLOR = 'rgba(22, 188, 212, 0.1)';
                var X_T1_COLOR = 'rgba(12,122,250,0.8)';

                var _bodyData = [
                    {
                        coord: ['R2', 'A3'],
                        mergeCells: true,
                        value: 'merged',
                    },
                    {
                        coord: ['R1', ['B4', 'C']],
                        mergeCells: true,
                        value: 'merged',
                    },
                    {
                        coord: [['R1', 'R2'], ['B2', 'B3']],
                        mergeCells: true,
                        value: 'merged',
                    },
                    {
                        coord: ['O', ['B2', 'not_exist']],
                        coordClamp: true,
                        mergeCells: true,
                        value: 'merged',
                        __expect: 'column O merged'
                    },
                    {
                        coord: ['T', ['A1', 'A31']],
                        mergeCells: true,
                        value: 'merged',
                    },
                    {
                        coord: ['S', null],
                        coordClamp: true,
                        mergeCells: true,
                        value: 'merged',
                        __expect: 'column S merged.'
                    },
                ];
                var _cornerData = [
                    {
                        coord: [[-1, -2], -1],
                        mergeCells: true,
                        value: 'merged',
                    }
                ];

                const _xData = [
                    {
                        value: 'R',
                        children: ['R1', {value: 'R2', size: CELL_SIZE_1}]
                    },
                    {
                        value: 'S'
                    },
                    {
                        value: 'T',
                        children: [
                            {
                                value: 'T1',
                                children: ['T11'],
                            }
                        ]
                    },
                    'O',
                    'P',
                ];
                const _yData = [
                    {
                        value: 'A',
                        children: ['A1', 'A2', {
                            value: 'A3',
                            children: ['A31', 'A32']
                        }]
                    }, {
                        value: 'B',
                        children: ['B1', 'B2', 'B3', 'B4']
                    }, {
                        value: 'C',
                    }, {
                        value: 'D',
                    }
                ];
                const MatrixClampOption = {
                    none: 0,
                    all: 1,
                    body: 2,
                    corner: 3,
                };

                // --- state ------
                let _xShowing = true;
                let _yShowing = true;
                let _convertToLayoutClampOpt = undefined;
                let _ignoreMergeCells = undefined;
                let _testCase = null;
                // ----------------

                function calcMeta() {
                    const xMeta = calcOneDim(_xData);
                    const yMeta = calcOneDim(_yData);
                    function calcOneDim(xyData) {
                        let levelCount = 0;
                        let leafCount = 0;
                        travel(xyData, 0, 0);
                        function travel(list, locatorStart, level) {
                            levelCount = Math.max(levelCount, level);
                            leafCount = Math.max(leafCount, locatorStart);
                            if (!list) {
                                return;
                            }
                            list.forEach((item, idx) => {
                                travel(item.children, locatorStart + idx, level + 1);
                            });
                        }
                        return {levelCount, leafCount};
                    }
                    const xUnitCount = xMeta.leafCount + (_yShowing ? yMeta.levelCount : 0);
                    const yUnitCount = yMeta.leafCount + (_xShowing ? xMeta.levelCount : 0);
                    return {xUnitCount, yUnitCount};
                }

                var option;
                option = {
                    backgroundColor: '#eee',
                    tooltip: {},
                    title: {
                        text: '',
                        right: 'center',
                    },
                    matrix: [{
                        // matrix 0
                        right: 10,
                        bottom: 10,
                        width: 180,
                        height: 80,
                        x: {
                            data: ['X1', 'X2', 'X3'],
                        },
                        y: {
                            data: ['Y1', 'Y2', 'Y3', 'Y4'],
                        },
                        body: {
                            data: [{
                                coord: [[0, 2], [1, 2]],
                                value: 'should be right-bottom',
                                mergeCells: true,
                            }]
                        },
                    }, {
                        // matrix 1
                        id: 'main_matrix',
                        right: 10,
                        left: 230,
                        top: 50,
                        bottom: 120,
                        tooltip: {
                            show: true,
                            formatter(params) {
                                return params.name;
                            }
                        },
                        x: {
                            label: {
                            },
                            itemStyle: {
                                color: X_COMMON_COLOR
                            },
                            levels: [null, {levelSize: LEVEL_SIZE_1}],
                            data: _xData
                        },
                        y: {
                            levelSize: 40,
                            data: _yData,
                        },
                        body: {
                            data: _bodyData,
                            label: {
                            },
                            itemStyle: {
                                color: BODY_COMMON_COLOR
                            }
                        },
                        corner: {
                            data: _cornerData,
                            itemStyle: {
                                borderWidth: 1,
                            },
                        }
                    }],
                    series: [{
                        type: 'scatter',
                        coordinateSystem: 'matrix',
                        matrixIndex: 1,
                        symbolSize: 30,
                        data: [
                            ['R1', 'A1', 10], ['R2', 'A1', 20], ['R1', 'A2', 30]
                        ],
                        label: {
                            show: true,
                            formatter: params => {
                                return params.data[2];
                            }
                        }
                    }],
                    graphic: {
                        elements: [{
                            left: 5,
                            y: 5,
                            id: 'info_bodyData',
                            type: 'text',
                            style: {
                                text: 'Check body cell merge and style:\n' + testHelper.printObject(_bodyData, {lineBreakMaxColumn: 40}),
                                fontSize: 7,
                            }
                        }, {
                            left: 140,
                            y: 5,
                            id: 'info_cornerData',
                            type: 'text',
                            style: {
                                text: 'Check corner cell merge and style:\n' + testHelper.printObject(_cornerData, {lineBreakMaxColumn: 40}),
                                fontSize: 7,
                            }
                        }, {
                            id: 'result_convertToLayout',
                            type: 'rect',
                            shape: {x: 0, y: 0, width: 0, height: 0},
                            ignore: true,
                            silent: true,
                            style: {
                                fill: 'rgba(210,20,100,0.3)',
                                stroke: 'rgba(210,20,100,0.8)',
                                lineWidth: 3,
                            }
                        }, {
                            id: 'result_assertionFailure',
                            type: 'text',
                            ignore: true,
                            silent: true,
                            left: 10,
                            bottom: 10,
                            style: {
                                text: 'Some Case Failed',
                                fill: 'red',
                                fontSize: 20,
                            }
                        }]
                    },
                };

                var chart = testHelper.create(echarts, 'main_edge_cases', {
                    title: [
                        'Edge cases.',
                        'Test both when **show/hide** matrix.x/y; different **clamp**; **ignoreCellMerge** or not.',
                        'drag to resize to test cell border alignment',
                        '(must not affect by subpixel optimize or rounding error)',
                    ],
                    height: 350,
                    option: option,
                    inputsStyle: 'compact',
                    draggable: true,
                    inputs: [
                        {
                            text: 'matrix.x show:',
                            type: 'select',
                            values: [true, false],
                            onchange() {
                                _xShowing = this.value;
                                chart.setOption({
                                    matrix: {
                                        id: 'main_matrix',
                                        x: {show: _xShowing},
                                    },
                                });
                                updateCaseView();
                            }
                        },
                        {
                            text: 'matrix.y show:',
                            type: 'select',
                            values: [true, false],
                            onchange() {
                                _yShowing = this.value;
                                chart.setOption({
                                    matrix: {
                                        id: 'main_matrix',
                                        y: {show: _yShowing},
                                    },
                                });
                                updateCaseView();
                            }
                        },
                        {
                            text: 'convertToLayout clamp:',
                            type: 'select',
                            options: [
                                {value: undefined}
                            ].concat(Object.keys(MatrixClampOption).map(key => ({
                                text: key,
                                value: MatrixClampOption[key],
                            }))),
                            onchange() {
                                _convertToLayoutClampOpt = this.value;
                                updateCaseView();
                            },
                        },
                        {
                            text: 'ignoreMergeCells:',
                            type: 'select',
                            values: [undefined, false, true],
                            onchange() {
                                _ignoreMergeCells = this.value;
                                updateCaseView();
                            },
                        },
                        {
                            type: 'br',
                        },
                        {
                            type: 'select',
                            text: 'convertToLayout test cases:',
                            options: [{value: 'do_nothing'}].concat([
                                {
                                    input: [],
                                    expectDefault: {
                                        rectNaN: {x: true, y: true, width: true, height: true},
                                        matrixXYLocatorRange: [[NaN, NaN], [NaN, NaN]]
                                    }
                                },
                                {
                                    input: ['R2', null],
                                    expectDefault: {
                                        rectNaN: {y: true, height: true},
                                        matrixXYLocatorRange: [[1, 1], [NaN, NaN]]
                                    }
                                },
                                {
                                    input: [['S', 'O'], NaN],
                                    expectDefault: {
                                        rectNaN: {y: true, height: true},
                                        matrixXYLocatorRange: [[2, 4], [NaN, NaN]]
                                    }
                                },
                                {
                                    input: [['R'], NaN],
                                    expectDefault: {
                                        rectNaN: {y: true, height: true},
                                        matrixXYLocatorRange: [[0, 1], [NaN, NaN]]
                                    }
                                },
                                {
                                    input: [NaN, 'A31'],
                                    expectDefault: {
                                        rectNaN: {x: true, width: true},
                                        matrixXYLocatorRange: [[NaN, NaN], [2, 2]]
                                    }
                                },
                                {
                                    input: [undefined, ['A32', 'B3']],
                                    expectDefault: {
                                        rectNaN: {x: true, width: true},
                                        matrixXYLocatorRange: [[NaN, NaN], [3, 6]]
                                    }
                                },
                                {
                                    input: [null, 'B'],
                                    expectDefault: {
                                        rectNaN: {x: true, width: true},
                                        matrixXYLocatorRange: [[NaN, NaN], [4, 7]]
                                    }
                                },
                                {
                                    input: ['S', 'A32'],
                                    expectDefault: {
                                        rectNaN: {},
                                        matrixXYLocatorRange: [[2, 2], [0, 9]]
                                    }
                                },
                                {
                                    input: ['T', 'B1'],
                                    expectDefault: {
                                        rectNaN: {},
                                        matrixXYLocatorRange: [[3, 3], [4, 4]]
                                    }
                                },
                                {
                                    input: [[-1, 1], [-1, 2]],
                                    expectDefault: {
                                        rectNaN: {},
                                        matrixXYLocatorRange: [[-2, 1], [-1, 3]]
                                    }
                                },
                                {
                                    input: ['R', -2],
                                    expectDefault: {
                                        rectNaN: {},
                                        matrixXYLocatorRange: [[0, 1], [-2, -2]]
                                    }
                                },
                            ].map(item => ({
                                text: testHelper.printObject(item.input),
                                value: item,
                            }))),
                            onchange() {
                                if (this.value === 'do_nothing') {
                                    return;
                                }
                                _testCase = this.value;
                                updateCaseView();
                            } // End of onchange
                        } // End of convertToLayout test cases
                    ]
                });

                function updateCaseView() {
                    performTest(function (assert) {
                        if (!_testCase) {
                            return;
                        }
                        const {input, expectDefault} = _testCase;
                        const shouldBeClampped = !(
                            _convertToLayoutClampOpt == null || _convertToLayoutClampOpt === MatrixClampOption.none
                        );
                        const isDefaultCase = !shouldBeClampped && !_ignoreMergeCells;

                        const meta = calcMeta();
                        let opt = undefined;
                        if (_convertToLayoutClampOpt != null) {
                            opt = opt || {};
                            opt.clamp = _convertToLayoutClampOpt;
                        }
                        if (_ignoreMergeCells != null) {
                            opt = opt || {};
                            opt.ignoreMergeCells = _ignoreMergeCells;
                        }

                        const result = chart.convertToLayout({matrixIndex: 1}, input, opt);
                        console.log('Call convertToLayout', 'input:', input, 'opt:', opt, 'result:', result);

                        assert(testHelper.getType(result) === 'object');
                        assert(testHelper.getType(result.rect) === 'object');
                        assert(testHelper.getType(result.rect.x) === 'number');
                        assert(testHelper.getType(result.rect.y) === 'number');
                        assert(testHelper.getType(result.rect.width) === 'number');
                        assert(testHelper.getType(result.rect.height) === 'number');
                        assert(testHelper.getType(result.matrixXYLocatorRange) === 'array');
                        assert(testHelper.getType(result.matrixXYLocatorRange[0]) === 'array');
                        assert(testHelper.getType(result.matrixXYLocatorRange[1]) === 'array');
                        assert(testHelper.getType(result.matrixXYLocatorRange[0][0]) === 'number');
                        assert(testHelper.getType(result.matrixXYLocatorRange[0][1]) === 'number');
                        assert(testHelper.getType(result.matrixXYLocatorRange[1][0]) === 'number');
                        assert(testHelper.getType(result.matrixXYLocatorRange[1][1]) === 'number');

                        ['x', 'y', 'width', 'height'].forEach(prop => {
                            if (isDefaultCase) {
                                if (expectDefault.rectNaN[prop]) {
                                    assert(eqNaN(result.rect[prop]));
                                }
                                else {
                                    assert(isFinite(result.rect[prop]));
                                }
                            }
                            else if (shouldBeClampped) {
                                assert(isFinite(result.rect[prop]));
                            }
                        });

                        if (isDefaultCase) {
                            assert(numEq(expectDefault.matrixXYLocatorRange[0][0], result.matrixXYLocatorRange[0][0]));
                            assert(numEq(expectDefault.matrixXYLocatorRange[0][1], result.matrixXYLocatorRange[0][1]));
                            assert(numEq(expectDefault.matrixXYLocatorRange[1][0], result.matrixXYLocatorRange[1][0]));
                            assert(numEq(expectDefault.matrixXYLocatorRange[1][1], result.matrixXYLocatorRange[1][1]));
                        }

                        return result;
                    });

                    function performTest(cb) {
                        let testFailed = false;
                        function assert(condition) {
                            if (!condition) {
                                testFailed = true;
                                console.error('assertion failed', new Error());
                            }
                        }

                        let result;
                        try {
                            result = cb(assert);
                        }
                        catch (err) {
                            testFailed = true;
                            console.error(err);
                        }

                        const COVER_SIZE = 10000; // Just a big enough number.
                        let indicatorShape = {x: 0, y: 0, width: 0, height: 0};
                        if (result) {
                            indicatorShape = {};
                            indicatorShape.x = eqNaN(result.rect.x) ? -COVER_SIZE / 2 : result.rect.x;
                            indicatorShape.y = eqNaN(result.rect.y) ? -COVER_SIZE / 2 : result.rect.y;
                            indicatorShape.width = eqNaN(result.rect.width) ? COVER_SIZE : result.rect.width;
                            indicatorShape.height = eqNaN(result.rect.height) ? COVER_SIZE : result.rect.height;;
                        }

                        chart.setOption({
                            graphic: {
                                elements: [{
                                    id: 'result_convertToLayout',
                                    shape: indicatorShape,
                                    ignore: testFailed,
                                }, {
                                    id: 'result_assertionFailure',
                                    ignore: !testFailed,
                                }]
                            },
                        });
                    }
                }

                function eqNaN(value) {
                    return value !== value;
                }

                function numEq(expect, actual) {
                    return eqNaN(expect)
                        ? eqNaN(actual)
                        : expect === actual;
                }

            });

        </script>





    </body>
</html>

